package com.dualsportmaps.android;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.os.StrictMode;

import com.dualsportmaps.android.DsmMapDownload.DsmMapDownloadException;
import com.dualsportmaps.android.DsmMapDownload.SavedDsmMap;
import com.dualsportmaps.android.model.DsmMap;
import com.dualsportmaps.android.model.DsmMapPhoto;
import com.dualsportmaps.android.model.DsmMapTrack;
import com.dualsportmaps.android.model.DsmMapWpt;
import com.dualsportmaps.android.shared.model.DsmMapPhotoProxy;
import com.dualsportmaps.android.shared.model.DsmMapProxy;
import com.dualsportmaps.android.shared.model.DsmMapTrackProxy;
import com.dualsportmaps.android.shared.model.DsmMapWptProxy;
import com.google.web.bindery.requestfactory.shared.Receiver;
import com.google.web.bindery.requestfactory.shared.ServerFailure;

public class DsmMapDownloadService extends Service {
	final Messenger mMessenger = new Messenger(new IncomingHandler());
	@Override    
	public IBinder onBind(Intent intent) {        
		return mMessenger.getBinder();    
	}
	
	@Override
	public void onCreate() {
		super.onCreate();
	}  
	
	@Override
	public void onDestroy() {
		super.onDestroy();
		this.stopSelf();
	}  
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {  
		return START_STICKY;
	}
	
	ArrayList<Messenger> mClients = new ArrayList<Messenger>(); 
	static final int MSG_REGISTER_CLIENT = 1;    
	static final int MSG_UNREGISTER_CLIENT = 2;
	static final int MSG_MAP_DOWNLOAD = 3;
	static final int MSG_TOAST = 4;
	static final int MSG_MAP_DOWNLOAD_STARTED = 5;
	static final int MSG_PROCESS_GPX = 6;
	static final int MSG_STOP_SERVICE = 7;
	
	class IncomingHandler extends Handler {        
		@Override        
		public void handleMessage(final Message msg) { 
			interruptStop = true;
			switch (msg.what) {                
				case MSG_REGISTER_CLIENT:                    
					mClients.add(msg.replyTo);                    
					break;                
				case MSG_UNREGISTER_CLIENT:                    
					mClients.remove(msg.replyTo);                    
					break; 
				case MSG_MAP_DOWNLOAD:
					try {
						downloadMapFromWeb(msg.getData().getString("dsmMapId"));
					} catch (DsmMapDownloadException e) {
						sendToast("Map download Error");
					}
					break;
				case MSG_PROCESS_GPX:
					try {
						String dsmMapId = ConvertGPX.convertToGoogle(new File(msg.getData().getString("filepath")), DsmMapDownloadService.this.getApplicationContext());
						gpxProcessed(dsmMapId);
					} catch (Throwable e) {
						e.getStackTrace();
						gpxProcessed("error");
					}
					break;
				case MSG_STOP_SERVICE:
					interruptStop = false;
					if(!waitingForDownload) {
						new Thread(new Runnable() {
							@Override
							public void run() {
								try {
									Thread.sleep(2*60*1000);
									if(!interruptStop) {
										System.out.println("Stopping Service");
										stopSelf();
										System.exit(0);
									}
								} catch (Throwable e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
							}}).start(); 
					}
					break;
				default:                    
					super.handleMessage(msg);
			}        
		}

	}
	
	private static void strictmode() {
//		try {
//	        Class<?> strictModeClass = Class.forName("android.os.StrictMode", true, Thread.currentThread()
//	                .getContextClassLoader());
//
//	        Class<?> threadPolicyClass = Class.forName("android.os.StrictMode$ThreadPolicy", true, Thread
//	                .currentThread().getContextClassLoader());
//
//	        Class<?> threadPolicyBuilderClass = Class.forName("android.os.StrictMode$ThreadPolicy$Builder", true,
//	                Thread.currentThread().getContextClassLoader());
//
//	        Method setThreadPolicyMethod = strictModeClass.getMethod("setThreadPolicy", threadPolicyClass);
//
//	        Method permitAllMethod = threadPolicyBuilderClass.getMethod("permitAll");
//	        Method buildMethod = threadPolicyBuilderClass.getMethod("build");
//
//	        Constructor<?> threadPolicyBuilderConstructor = threadPolicyBuilderClass.getConstructor();
//	        Object threadPolicyBuilderObject = threadPolicyBuilderConstructor.newInstance();
//
//	        Object obj = permitAllMethod.invoke(threadPolicyBuilderObject);
//
//	        Object threadPolicyObject = buildMethod.invoke(obj);
//	        setThreadPolicyMethod.invoke(strictModeClass, threadPolicyObject);
//
//	    } catch (Exception ex) {
//	    	ex.printStackTrace();
//	    }
		if(android.os.Build.VERSION.SDK_INT >= 9) {
		    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
		     .permitAll()
		     .build();
		    StrictMode.setThreadPolicy(policy);
		}
	}
	
	private static boolean waitingForDownload = false;
	private static boolean interruptStop = false;
	
	private synchronized void downloadMapFromWeb(String dsmMapId) throws DsmMapDownloadException {
		strictmode();
		DsmConnectionFactory.authenticateDsmAppUser();
		final DsmMapDownload dsmMap = new DsmMapDownload(dsmMapId);
		waitingForDownload = true;
		final SavedDsmMap newMap = new SavedDsmMap();
		DsmConnectionFactory.getDsmConnection().getDsmMap(dsmMapId).fire(new Receiver<DsmMapProxy>() {
			@Override
			public void onSuccess(DsmMapProxy response) {
				downloadMapDetailsFromWeb(newMap,response, dsmMap);
			}

			@Override
			public void onFailure(ServerFailure error) {
				sendToast("Download map failure.");
			}
		});
		while(waitingForDownload) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {}
		}
	}
	
	private void downloadMapDetailsFromWeb(final SavedDsmMap newMap, DsmMapProxy response, final DsmMapDownload dsmMap) {
		boolean mapUpdated = true;
		if(dsmMap.map != null) 
			if(response.getDsmMapTS().equals(dsmMap.map.getDsmMapTS())) {
				mapUpdated = false;
			}
		if(mapUpdated) {
			final String dsmMapId = response.getDsmMapId();
			newMap.map = new DsmMap(
				response.getDsmMapId(), response.getDsmMapName(), response.getDsmMapDesc(),
				response.getDsmMapBound1Lat(), response.getDsmMapBound1Lng(),
				response.getDsmMapBound2Lat(), response.getDsmMapBound2Lng(), response.getDsmMapTS(),
				response.getDsmAppUserId(), response.isDsmMapViewable(), response.getDsmMapMaxZoom(),
				response.getDsmAppUserHandle());
			response = null;
			try {
				if(newMap.map.getDsmMapName().equals("All tracks in search area.")) {
					newMap.map.setDsmMapName(null);
				}
			} catch (Exception e) {
			}
			dsmMapDownloadedStarted();
			if(newMap.map.getDsmMapName() == null) {
				newMap.map.setDsmMapId("SEARCHRESULTS");
				sendToast("Loading search results.");
			}
			else if(newMap.map.getDsmMapId() != null) {
				sendToast(newMap.map.getDsmMapName() + " is updating.");
			}  
			try {
				DsmConnectionFactory.getDsmConnection().getDsmMapTracks(dsmMapId).fire(new Receiver<List<DsmMapTrackProxy>>() {
					@Override
					public void onFailure(ServerFailure error) {
						sendToast( "Track download failure.");
					}
					@Override
					public void onSuccess(List<DsmMapTrackProxy> response) {
						for(DsmMapTrackProxy track : response) {
							DsmMapTrack tdsmtrack = new DsmMapTrack(track.getDsmMapTrackGooglePoints(),track.getDsmMapTrackGoogleLevels(), track.getDsmMapTrackColor(), track.getDsmMapTrackBound1Lat(),track.getDsmMapTrackBound1Lng(),track.getDsmMapTrackBound2Lat(),track.getDsmMapTrackBound2Lng());
							tdsmtrack.setDsmMapTrackName(track.getDsmMapTrackName());
							tdsmtrack.setDsmMapTrackDistance(track.getDsmMapTrackDistance());
							tdsmtrack.setDsmMapTrackDifficulty(track.getDsmMapTrackDifficulty());
							newMap.tracks.add(tdsmtrack);
							track = null;
						}
						response = null;
						DsmConnectionFactory.getDsmConnection().getDsmMapWpts(dsmMapId).fire(new Receiver<List<DsmMapWptProxy>>() {
							@Override
							public void onFailure(ServerFailure error) {
								sendToast( "Waypoint download failure.");
							}
							@Override
							public void onSuccess(List<DsmMapWptProxy> response) {
								newMap.waypoints = new ArrayList<DsmMapWpt>();
								for(DsmMapWptProxy wpt : response) {
									newMap.waypoints.add(new DsmMapWpt(
											wpt.getDsmMapWptId(),
											wpt.getDsmMapId(),
											wpt.getDsmMapWptName(),
											wpt.getDsmMapWptDesc(),
											wpt.getDsmMapWptLat(),
											wpt.getDsmMapWptLng(),
											wpt.getDsmMapWptIcon()
											));
									wpt = null;
								}
								response = null;
								DsmConnectionFactory.getDsmConnection().getDsmMapPhotos(dsmMapId).fire(new Receiver<List<DsmMapPhotoProxy>>() {
									@Override
									public void onFailure(ServerFailure error) {
										sendToast( "Photo download failure.");
									}
									@Override
									public void onSuccess(List<DsmMapPhotoProxy> response) {
										newMap.photos = new ArrayList<DsmMapPhoto>();
										for(DsmMapPhotoProxy photo : response) {
											DsmMapPhoto tphoto = new DsmMapPhoto();
											tphoto.setDsmAppUserHandle(photo.getDsmAppUserHandle());
											tphoto.setDsmAppUserId(photo.getDsmAppUserId());
											tphoto.setDsmMapId(photo.getDsmMapId());
											tphoto.setDsmMapPhotoCamera(photo.getDsmMapPhotoCamera());
											tphoto.setDsmMapPhotoCaption(photo.getDsmMapPhotoCaption());
											tphoto.setDsmMapPhotoId(photo.getDsmMapPhotoId());
											tphoto.setDsmMapPhotoLat(photo.getDsmMapPhotoLat());
											tphoto.setDsmMapPhotoLng(photo.getDsmMapPhotoLng());
											tphoto.setDsmMapPhotoTS(photo.getDsmMapPhotoTS());
											newMap.photos.add(tphoto);
											photo = null;
										}
										response = null;
										DsmMapDownload.saveDsmMap(newMap,DsmMapDownloadService.this.getApplicationContext());
										dsmMapDownloaded(newMap.map.getDsmMapId());
										waitingForDownload = false;
									}
								});	
							}
						});
					}
				});
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.getCause().printStackTrace();
				e.printStackTrace();
				dsmMapDownloaded(null);
				waitingForDownload = false;
			}
		} else {
			response = null;
			dsmMapDownloaded(null);
			waitingForDownload = false;	
		}
	}

	private void sendToast(String toastMessage) {
		sendMessageToClients(MSG_TOAST,toastMessage);
	}
	
	private void dsmMapDownloaded(String dsmMapId) {
		sendMessageToClients(MSG_MAP_DOWNLOAD,dsmMapId);
	}
	
	private void dsmMapDownloadedStarted() {
		sendMessageToClients(MSG_MAP_DOWNLOAD_STARTED,"");
	}
	
	private void gpxProcessed(String dsmMapId) {
		sendMessageToClients(MSG_PROCESS_GPX,dsmMapId);
	}
	
	private void sendMessageToClients(int type, String message) {
		for (int i=mClients.size()-1; i>=0; i--) {                        
			try {                    
				Message msg = Message.obtain(null,type);
				Bundle data = new Bundle();
				data.putString("message", message);
				msg.setData(data);
				mClients.get(i).send(msg);                        
			} catch (RemoteException e) {                            
				// The client is dead.  Remove it from the list;                            
				// we are going through the list from back to front                            
				// so this is safe to do inside the loop.                            
				mClients.remove(i);                        
			}                   
		} 
	}
	
}
